{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6a9bc9fb-3914-49fc-b3cf-4e59d22fd8a2",
   "metadata": {},
   "outputs": [],
   "source": [
    "from gs_quant.session import Environment\n",
    "from gs_quant.instrument import OptionStyle\n",
    "from gs_quant.backtests.strategy import Strategy\n",
    "from gs_quant.backtests.triggers import *\n",
    "from gs_quant.backtests.actions import *\n",
    "from gs_quant.backtests.equity_vol_engine import *\n",
    "from gs_quant.backtests.generic_engine import GenericEngine\n",
    "from gs_quant.target.measures import Price\n",
    "from datetime import datetime, date\n",
    "\n",
    "import gs_quant.risk as risk"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2a6175aa-bd47-4cd3-bead-dcebe4f5ea8d",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Initialize session\n",
    "from gs_quant.session import GsSession\n",
    "GsSession.use(client_id=None, client_secret=None, scopes=('run_analytics',)) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5e2c6435-b2a0-4824-ae5c-4d4ef0f42ee4",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Define backtest dates\n",
    "start_date = date(2021, 4, 1)\n",
    "end_date = datetime.today().date()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "62435b59-ec26-4d5b-9b74-fd72396a468d",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Define instruments for strategy\n",
    "# Portfolio of two eq options\n",
    "call = EqOption('.STOXX50E', expiration_date='1m', strike_price='ATM', option_type=OptionType.Call, option_style=OptionStyle.European, name='call')\n",
    "put = EqOption('.STOXX50E', expiration_date='1m', strike_price='ATM', option_type=OptionType.Put, option_style=OptionStyle.European, name='put')\n",
    "portfolio = Portfolio(name='portfolio', priceables=[call, put])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ea1412f0-055e-4954-9d05-527e93018181",
   "metadata": {},
   "source": [
    "### Entering a position monthly"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "adb4fc9d-1c23-40a6-b109-3ca8425ad623",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Trade the position monthly without any scaling\n",
    "trade_action = EnterPositionQuantityScaledAction(priceables=portfolio, trade_duration='1m', name='act')\n",
    "trade_trigger = PeriodicTrigger(trigger_requirements=PeriodicTriggerRequirements(start_date=start_date, end_date=end_date, frequency='1m'),\n",
    "                                actions=trade_action)\n",
    "\n",
    "strategy = Strategy(None, trade_trigger)\n",
    "\n",
    "# Run backtest daily\n",
    "GE = GenericEngine()\n",
    "backtest = GE.run_backtest(strategy, start=start_date, end=end_date, frequency='1b', show_progress=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "932678aa-cf61-4c71-b057-55a3ab81c241",
   "metadata": {},
   "outputs": [],
   "source": [
    "# View results summary\n",
    "backtest.result_summary"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9c126b67-aecf-4493-9ac6-397b984852ed",
   "metadata": {},
   "outputs": [],
   "source": [
    "# View backtest trade ledger\n",
    "backtest.trade_ledger()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3b612c5d-3855-4a23-bff9-cca08fdfd767",
   "metadata": {},
   "outputs": [],
   "source": [
    "# View Mark to Market\n",
    "pd.DataFrame({'Generic backtester': backtest.result_summary[Price]}).plot(figsize=(10, 6), title='Mark to market')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a1d2cf05-0622-4899-af32-be9dc0fad840",
   "metadata": {},
   "outputs": [],
   "source": [
    "# View Performance\n",
    "pd.DataFrame({'Generic backtester': backtest.result_summary['Cumulative Cash'] + backtest.result_summary[Price]}).plot(figsize=(10, 6), title='Performance')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5d3c2217-f45b-4c84-a64f-afdc9e91940f",
   "metadata": {},
   "source": [
    "### Scaling quantity"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7998da4c-0a08-4698-97af-169654f1f11a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Scale the position quantity (no. of options) by 2\n",
    "trade_action_scaled = EnterPositionQuantityScaledAction(priceables=portfolio, trade_duration='1m', trade_quantity=2, name='scaled_act')\n",
    "trade_trigger_scaled = PeriodicTrigger(trigger_requirements=PeriodicTriggerRequirements(start_date=start_date, end_date=end_date, frequency='1m'),\n",
    "                                actions=trade_action_scaled)\n",
    "\n",
    "strategy = Strategy(None, trade_trigger_scaled)\n",
    "\n",
    "# Run backtest daily\n",
    "GE = GenericEngine()\n",
    "backtest = GE.run_backtest(strategy, start=start_date, end=end_date, frequency='1b', show_progress=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "14d7e2f3-8f06-4a89-9486-9f5fb35363f1",
   "metadata": {},
   "outputs": [],
   "source": [
    "# View results summary. Note that MtM and cash payments are double\n",
    "backtest.result_summary"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f1d811a8-2ca1-467d-8d1a-a8b164fbfd23",
   "metadata": {},
   "outputs": [],
   "source": [
    "# View backtest trade ledger. Note that all values are double\n",
    "backtest.trade_ledger()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9f805bfe-9f5f-402e-a21e-0e08e40a55de",
   "metadata": {},
   "outputs": [],
   "source": [
    "# View Mark to Market\n",
    "pd.DataFrame({'Generic backtester': backtest.result_summary[Price]}).plot(figsize=(10, 6), title='Mark to market')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bd2576e9-de1b-4955-80fa-632c02897e68",
   "metadata": {},
   "outputs": [],
   "source": [
    "# View Performance\n",
    "pd.DataFrame({'Generic backtester': backtest.result_summary['Cumulative Cash'] + backtest.result_summary[Price]}).plot(figsize=(10, 6), title='Performance')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b52d3f47-ab87-4074-ae34-3ef3bb7c54c9",
   "metadata": {},
   "source": [
    "### Scaling a risk measure"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2dff6a31-583b-4858-8c7c-ef259f1a6659",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Initial and final Vega of the portfolio\n",
    "with PricingContext(start_date):\n",
    "    start_vega = portfolio.calc(risk.EqVega)\n",
    "\n",
    "with PricingContext(end_date):\n",
    "    end_vega = portfolio.calc(risk.EqVega)\n",
    "\n",
    "print(start_vega.aggregate())\n",
    "print(end_vega.aggregate())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "01384407-a6c2-4083-8577-f8a98468a429",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Scale the position vega to 100\n",
    "trade_action_scaled = EnterPositionQuantityScaledAction(priceables=portfolio, trade_duration='1m', trade_quantity=100, trade_quantity_type=BacktestTradingQuantityType.vega, name='scaled_vega_act')\n",
    "trade_trigger_scaled = PeriodicTrigger(trigger_requirements=PeriodicTriggerRequirements(start_date=start_date, end_date=end_date, frequency='1m'),\n",
    "                                actions=trade_action_scaled)\n",
    "\n",
    "strategy = Strategy(None, trade_trigger_scaled)\n",
    "\n",
    "# Run backtest daily\n",
    "GE = GenericEngine()\n",
    "backtest = GE.run_backtest(strategy, start=start_date, end=end_date, frequency='1b', show_progress=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "10ef8a2a-b290-40dc-ad05-e070897652c3",
   "metadata": {},
   "outputs": [],
   "source": [
    "# View results summary. Note that MtM and cash payments are around 10x larger, as vega was scaled by around 10x\n",
    "backtest.result_summary"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "25b76af9-3b23-4b56-9307-b88dc7c3c5ef",
   "metadata": {},
   "outputs": [],
   "source": [
    "# View backtest trade ledger. Note that all values are around 10x larger than without scaling\n",
    "backtest.trade_ledger()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4ccd5bcd-bd52-4fb2-ba29-e2c72c0d3892",
   "metadata": {},
   "outputs": [],
   "source": [
    "# View Mark to Market\n",
    "pd.DataFrame({'Generic backtester': backtest.result_summary[Price]}).plot(figsize=(10, 6), title='Mark to market')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f14aabf9-1964-4002-9a4a-48032438f53d",
   "metadata": {},
   "outputs": [],
   "source": [
    "# View Performance\n",
    "pd.DataFrame({'Generic backtester': backtest.result_summary['Cumulative Cash'] + backtest.result_summary[Price]}).plot(figsize=(10, 6), title='Performance')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b5984b12-10ce-498a-9f78-335bd135aabe",
   "metadata": {},
   "source": [
    "### NAV Trading"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "417169e2-addf-4c0b-a355-cff4f35b106a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Create a NAV-based action that starts with 100 available to spend\n",
    "start_date = date(2022, 1, 1)\n",
    "end_date = datetime.today().date()\n",
    "\n",
    "trade_action_scaled = EnterPositionQuantityScaledAction(priceables=portfolio, trade_duration='1m', trade_quantity=100, trade_quantity_type=BacktestTradingQuantityType.NAV, name='nav_act')\n",
    "trade_trigger_scaled = PeriodicTrigger(trigger_requirements=PeriodicTriggerRequirements(start_date=start_date, end_date=end_date, frequency='1m'),\n",
    "                                actions=trade_action_scaled)\n",
    "\n",
    "strategy = Strategy(None, trade_trigger_scaled)\n",
    "\n",
    "# Run backtest daily\n",
    "GE = GenericEngine()\n",
    "backtest = GE.run_backtest(strategy, start=start_date, end=end_date, frequency='1b', show_progress=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3832acf6-370d-4a77-ab57-219134a9ee6f",
   "metadata": {},
   "outputs": [],
   "source": [
    "# View results summary. The action trades the starting cash and only uses proceeds from selling options after that: note that Cumulative Cash is always the initial trade quantity\n",
    "backtest.result_summary"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3050b635-46dc-4725-bebb-e017b69efc47",
   "metadata": {},
   "outputs": [],
   "source": [
    "# View backtest trade ledger\n",
    "backtest.trade_ledger()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "aeaf8396-b874-40b3-a4e3-78c9959aeb9a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# View Mark to Market. If zero right before an order, future orders are all zero\n",
    "pd.DataFrame({'Generic backtester': backtest.result_summary[Price]}).plot(figsize=(10, 6), title='Mark to market')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a0db5cf7-1e40-4505-8324-740028aebc30",
   "metadata": {},
   "outputs": [],
   "source": [
    "# View Performance. Maximum loss is 100 if there is no short selling\n",
    "pd.DataFrame({'Generic backtester': backtest.result_summary['Cumulative Cash'] + backtest.result_summary[Price]}).plot(figsize=(10, 6), title='Performance')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
